// 缩进敏感的解析器 - Python 风格
const std = @import("std");
const lexer = @import("lexer.zig");
const array_list = @import("array_list.zig");
const ArrayList = array_list.ArrayList;

/// 缩进级别
pub const IndentLevel = struct {
    spaces: usize,
    
    pub fn fromSpaces(spaces: usize) IndentLevel {
        return .{ .spaces = spaces };
    }
    
    pub fn compare(self: IndentLevel, other: IndentLevel) std.math.Order {
        return std.math.order(self.spaces, other.spaces);
    }
};

/// 缩进栈 - 跟踪当前缩进级别
pub const IndentStack = struct {
    levels: ArrayList(IndentLevel),
    allocator: std.mem.Allocator,
    
    pub fn init(allocator: std.mem.Allocator) IndentStack {
        var stack = IndentStack{
            .levels = ArrayList(IndentLevel).init(allocator),
            .allocator = allocator,
        };
        // 初始缩进级别为 0
        stack.levels.append(IndentLevel.fromSpaces(0)) catch {};
        return stack;
    }
    
    pub fn deinit(self: *IndentStack) void {
        self.levels.deinit();
    }
    
    pub fn current(self: *IndentStack) IndentLevel {
        return self.levels.items[self.levels.items.len - 1];
    }
    
    pub fn push(self: *IndentStack, level: IndentLevel) !void {
        try self.levels.append(level);
    }
    
    pub fn pop(self: *IndentStack) ?IndentLevel {
        if (self.levels.items.len <= 1) return null;
        const last_idx = self.levels.items.len - 1;
        const level = self.levels.items[last_idx];
        self.levels.items.len -= 1;
        return level;
    }
    
    pub fn depth(self: *IndentStack) usize {
        return self.levels.items.len - 1;
    }
};

/// 计算行首的缩进空格数
pub fn countIndent(line: []const u8) usize {
    var count: usize = 0;
    for (line) |c| {
        if (c == ' ') {
            count += 1;
        } else if (c == '\t') {
            count += 4; // 1 tab = 4 spaces
        } else {
            break;
        }
    }
    return count;
}

/// 检查是否是块开始（以冒号结尾）
pub fn isBlockStart(tokens: []const lexer.Token, pos: usize) bool {
    if (pos >= tokens.len) return false;
    
    // 向后查找最近的非空白 token
    var i = pos;
    while (i > 0) : (i -= 1) {
        const token = tokens[i - 1];
        if (token.type == .colon) {
            return true;
        }
        // 如果遇到分号或大括号，说明不是块开始
        if (token.type == .semicolon or 
            token.type == .lbrace or 
            token.type == .rbrace) {
            return false;
        }
    }
    return false;
}

/// 插入虚拟的大括号 token
pub fn insertBraces(
    allocator: std.mem.Allocator,
    source: []const u8,
    tokens: []const lexer.Token,
) ![]lexer.Token {
    var result = ArrayList(lexer.Token).init(allocator);
    defer result.deinit();
    
    var indent_stack = IndentStack.init(allocator);
    defer indent_stack.deinit();
    
    var current_line: usize = 1;
    var line_start_indent: usize = 0;
    var expecting_indent = false;
    
    for (tokens, 0..) |token, i| {
        // 检测新行
        if (token.line > current_line) {
            current_line = token.line;
            
            // 计算新行的缩进
            line_start_indent = token.column - 1;
            const current_indent = IndentLevel.fromSpaces(line_start_indent);
            const stack_indent = indent_stack.current();
            
            if (expecting_indent) {
                // 期待缩进增加
                if (current_indent.compare(stack_indent) == .gt) {
                    // 缩进增加，插入 {
                    try result.append(lexer.Token{
                        .type = .lbrace,
                        .lexeme = "{",
                        .line = token.line,
                        .column = 1,
                    });
                    try indent_stack.push(current_indent);
                    expecting_indent = false;
                }
            } else {
                // 检查缩进减少
                while (current_indent.compare(indent_stack.current()) == .lt) {
                    // 缩进减少，插入 }
                    _ = indent_stack.pop();
                    try result.append(lexer.Token{
                        .type = .rbrace,
                        .lexeme = "}",
                        .line = token.line,
                        .column = 1,
                    });
                }
            }
        }
        
        // 检查是否是块开始（冒号）
        if (token.type == .colon and isBlockStart(tokens[0..i+1], i)) {
            expecting_indent = true;
            // 不添加冒号，它会被转换为 {
        } else {
            try result.append(token);
        }
    }
    
    // 文件结束，关闭所有未关闭的块
    while (indent_stack.depth() > 0) {
        _ = indent_stack.pop();
        try result.append(lexer.Token{
            .type = .rbrace,
            .lexeme = "}",
            .line = current_line + 1,
            .column = 1,
        });
    }
    
    return try result.toOwnedSlice();
}

/// 预处理：将缩进风格转换为大括号风格
pub fn preprocessIndent(
    allocator: std.mem.Allocator,
    source: []const u8,
    tokens: []const lexer.Token,
) ![]lexer.Token {
    // 检查是否使用了缩进风格（查找冒号后没有大括号的情况）
    var uses_indent_style = false;
    for (tokens, 0..) |token, i| {
        if (token.type == .colon) {
            // 检查后面是否有大括号
            if (i + 1 < tokens.len) {
                const next = tokens[i + 1];
                if (next.type != .lbrace) {
                    uses_indent_style = true;
                    break;
                }
            }
        }
    }
    
    if (uses_indent_style) {
        return try insertBraces(allocator, source, tokens);
    } else {
        // 不使用缩进风格，直接返回原 tokens
        return try allocator.dupe(lexer.Token, tokens);
    }
}

test "indent counting" {
    const testing = std.testing;
    
    try testing.expectEqual(@as(usize, 0), countIndent("hello"));
    try testing.expectEqual(@as(usize, 4), countIndent("    hello"));
    try testing.expectEqual(@as(usize, 8), countIndent("        hello"));
    try testing.expectEqual(@as(usize, 4), countIndent("\thello"));
}

test "indent stack" {
    const testing = std.testing;
    
    var stack = IndentStack.init(testing.allocator);
    defer stack.deinit();
    
    try testing.expectEqual(@as(usize, 0), stack.depth());
    
    try stack.push(IndentLevel.fromSpaces(4));
    try testing.expectEqual(@as(usize, 1), stack.depth());
    
    try stack.push(IndentLevel.fromSpaces(8));
    try testing.expectEqual(@as(usize, 2), stack.depth());
    
    _ = stack.pop();
    try testing.expectEqual(@as(usize, 1), stack.depth());
}
